#!coding:utf-8
import cPickle
from pytz import UTC, os
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions, permissions
import datetime
from datetime import timedelta

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework import generics
from rest_framework.generics import GenericAPIView


from celery import current_app
from celery.signals import task_sent
from cvirt.common import utils, exception,translate as _
import rsa
from cvirt.manager.models import Cluster, Server, Datacenter, Instance
from cvirt.common import  config
from cvirt.tasks import clazz

conf = config.load_settings()

from django.contrib import auth

def update_sent_state(sender=None, id=None, **kwargs):
    # the task may not exist if sent using `send_task` which
    # sends tasks by name, so fall back to the default result backend
    # if that is the case.
    task = current_app.tasks.get(sender)
    backend = task.backend if task else current_app.backend

    backend.store_result(id, None, "sent")
task_sent.connect(update_sent_state)


class ExpiringTokenAuthentication2(TokenAuthentication):
    """
    token过期检查
    """
    def authenticate_credentials(self, key):
        user,token = super(ExpiringTokenAuthentication2,self).authenticate_credentials(key)

        # This is required for the time comparison
        #utc_now = datetime.datetime.utcnow
        utc_now = datetime.datetime.now(tz=UTC)

        if token.created < utc_now - timedelta(hours=6):
            raise exceptions.AuthenticationFailed('Token has expired')

        return user, token


class ExpiringTokenAuthentication(TokenAuthentication):
    """
    token过期检查
    """
    def _check_license(self):
        try:
            with file("/etc/licenseinfo") as key:
                msg = key.read()
                dmsg = rsa.transform.binascii.a2b_hex(msg)
                with file(os.path.join(os.path.dirname(__file__), 'tcloudpriv')) as prikeyfile:
                    dmsg = rsa.decrypt(dmsg, rsa.PrivateKey.load_pkcs1(prikeyfile.read()))
                prikeyfile.close()
                licenseinfo = cPickle.loads(dmsg)
            key.close()
        except:
            raise exceptions.AuthenticationFailed('NoLicenseExist')

        #just check time period
        if licenseinfo['time'] == -1 or datetime.datetime.now().date() > licenseinfo['time']:
            raise exceptions.AuthenticationFailed('licenseExpire')

        if licenseinfo['hardwareid'] != utils.hardware_uuid():
            raise exceptions.AuthenticationFailed('licenseExpire')

        insts = Instance.objects.count()
        available = licenseinfo["inst"] - insts
        if available < 0:
            raise exceptions.AuthenticationFailed('licenseExaust')

    def authenticate(self, request):
        '''
            扩展token认证方式，默认是通过http头部的方式，这里添加get参数
        '''
        token = request.GET.get('token',None)
        if token:
            request.META['HTTP_AUTHORIZATION'] = "token %s" % token
        return super(ExpiringTokenAuthentication,self).authenticate(request)

    def authenticate_credentials(self, key):
        user,token = super(ExpiringTokenAuthentication,self).authenticate_credentials(key)

        # This is required for the time comparison
        #utc_now = datetime.datetime.utcnow
        utc_now = datetime.datetime.now(tz=UTC)
        if conf.get_bool("license.check"):
            self._check_license()
        if token.created < utc_now - timedelta(hours=6):
            raise exceptions.AuthenticationFailed('Token has expired')

        return user, token

class ExpiringObtainAuthToken(ObtainAuthToken):
    """renew token"""
    def post(self, request):
        serializer = self.serializer_class(data=request.DATA)
        if serializer.is_valid():
            token, created = Token.objects.get_or_create(user=serializer.object['user'])
            if not created:
                token.created = datetime.datetime.now()
                token.save()
            #auth.login(request, serializer.object['user'])
            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class BaseListAPIView(generics.ListCreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (ExpiringTokenAuthentication,)

class BaseRetriveAPIView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (ExpiringTokenAuthentication,)


class NonModelBaseAPIView(GenericAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (ExpiringTokenAuthentication,)

class NamedAPIViewMixIn(object):
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (ExpiringTokenAuthentication,)
    '''
    view中我们遵循下面的约定：
    1.angularjs中定义resource url只保留get，post两个方法，在get和post基础上
    添加action来区分操作
    2.NamedAPIViewMixIn中我们定义对应action的方法，NamedAPIViewMixIn将请求路由到制定的方法
    example:
    class testapiview(NamedAPIViewMixIn,GenericAPIView):
        def start(self,request,*args,**kwargs):
            ...

    '''
    def get(self, request, *args, **kwargs):
        self.pk = kwargs.get('pk')
        if kwargs.get('action'):
            return self._dispatch(request,*args,**kwargs)
        return self._get(request,*args,**kwargs)

    def get_query_string(self,key):
        return self.request.QUERY_PARAMS.get(key,None)

    def get_int_param(self,key):
        value = self.get_params(key)
        try:
            return int(value)
        except:
            pass

    def get_bool_param(self,key):
        value = self.get_params(key)
        if value:
            if value.lower()=='true':
                return True
            if value.lower()== 'false':
                return False
        return bool(value)

    def get_params(self,key):
        params = self.request.DATA.get(key)
        if type(params) == dict:
            return utils.safedict(params)
        return params

    def _dispatch(self,request,*args,**kwargs):
        self.action = kwargs.get('action')
        self.pk = kwargs.get('pk')
        if self.action:
            if hasattr(self,self.action):
                try:
                    return getattr(self,self.action)(request,*args,**kwargs)
                except exception.ServiceNotFound as e:
                    return Response(_("%s节点服务未启动，请确认" % e.host),status.HTTP_400_BAD_REQUEST)
        return Response(_("请求的操作%s不存在" % self.action),status=400)

    def post(self,request, *args, **kwargs):
        if kwargs.get('action'):
            return self._dispatch(request,*args,**kwargs)
        return Response(_("POST操作需要action参数"),status=400)

    def paginate(self,request,data_queryset,serializer_class):
        "获取分页信息的帮助方法"
        pagesize = request.GET.get("page_size")
        startpage = request.GET.get("current_page")
        scope = request.GET.get('scope')
        #do not need paginate
        if scope == 'all':
            serializer = serializer_class(data_queryset.all(),many=True)
            return {"data":serializer.data}

        pagesize = 5 if not pagesize else int(pagesize)
        startpage = 1 if not startpage else int(startpage)

        data = data_queryset[(startpage-1)*pagesize:startpage*pagesize]

        serializer = serializer_class(data, many=True)
        total_count = data_queryset.count()
        if total_count%pagesize == 0:
            total_page = total_count/pagesize
        else:
            total_page = total_count/pagesize+1

        return {"total_page":total_page,"total_count":total_count,"data":serializer.data}

    def auto_select_host(self,qset):
        servers = dict(map(lambda s: (s.host_name, s.id), qset))
        hostid = servers.get(clazz.pick_host(clazz.ping(*servers.keys())))
        if hostid:
            return Server.objects.get_or_none(pk=hostid)

class TreeListView(NonModelBaseAPIView):
    """构造左侧树结构"""
    def _gen_cluster_children(self,cluster):
        """获取服务器树形结构"""
        servers = Server.objects.filter(cluster=cluster)
        cluster_children = []
        for server in servers:
            _child = {
                "id":"h%s" % server.id,
                "did":server.id,
                "name":server.host_name,
                "url":"#/host/%s" % server.id,
                "icon":"/static/images/host.png",
                "children":self._get_host_children(server)
            }
            cluster_children.append(_child)
        return cluster_children

    def _get_host_children(self,host):
        insts = Instance.objects.filter(host=host)
        return [dict(id="v%s" % inst.id,did=inst.id,name=inst.name,url="#/vm/%s" % inst.id,
                     icon="/static/images/vmstatus/%s.png" % inst.status.lower(),type='vm') for inst in insts]

    def get(self,request,*args,**kwargs):
        datacenter = Datacenter.objects.first()
        if datacenter:
            clusters = Cluster.objects.filter(datacenter=datacenter)
            datacenter_children = []
            for cluster in clusters:
                cluster_children = self._gen_cluster_children(cluster)
                dc_child = {
                    "id": "c%s" % cluster.id,
                    "did":cluster.id,
                    "name":cluster.name,
                    "url":"#/cluster/%s"%cluster.id,
                    "icon":"/static/images/cluster.png",
                    "children":cluster_children
                }
                datacenter_children.append(dc_child)

            rt = [
                {
                    "name": "书签管理",
                    "icon": "/static/images/bookmark.png",
                    "url": "#/shortcuts"
                },
                {
                    "id": "d%s" %datacenter.id,
                    "did":datacenter.id,
                    "name":datacenter.name,
                    "icon":"/static/images/datacenter.png",
                    "url":"#/datacenter/%s" % datacenter.id,
                    "children":datacenter_children
                },
                {
                    "name": "模板",
                    "icon": "/static/images/template.png",
                    "url": "#/templates"
                },
                # {
                #     "name": "网络安全",
                #     "icon": "/static/images/security.png",
                #     "url": "#/networks"
                # },
                # {
                #     "name": "备份策略",
                #     "icon": "/static/images/host.png",
                #     "url": "#/backupstrategies"
                # },
                {
                    "name": "方案管理",
                    "icon": "/static/images/plan.png",
                    "url": "#/proposals"
                },
                # {
                #     "name": "终端管理",
                #     "icon": "/static/images/client.png",
                #     "url": "#/architects"
                # },
                # {
                #     "name": "全局配置",
                #     "icon": "/static/images/host.png",
                #     "url": "#/globalconfigs"
                # },
                {
                    "name": "用户管理",
                    "icon": "/static/images/user.png",
                    "url": "#/users"
                },
                {
                    "name": "平台信息",
                    "icon": "/static/images/platform.png",
                    "url": "#/platform"
                }
            ]
            return Response(rt)
